package cn.pupil.springframework.beans.factory.support;

import cn.pupil.springframework.beans.BeansException;
import cn.pupil.springframework.beans.factory.FactoryBean;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Description: FactoryBean注册服务接口
 * @Author: pupil
 * @Date: 2024/11/12 下午 5:45
 */
public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry {

    /**
     * Cache of singleton objects created by FactoryBeans: FactoryBean name --> object
     * FactoryBean创建的单例对象缓存：FactoryBean名称-->对象
     */
    private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>();

    /**
     * 获取缓存中的单例对象
     *
     * @param beanName bean名
     * @return
     */
    protected Object getCachedObjectForFactoryBean(String beanName) {
        Object object = this.factoryBeanObjectCache.get(beanName);
        return (object != NULL_OBJECT ? object : null);
    }

    /**
     * 获取对象
     *
     * @param factory  FactoryBean
     * @param beanName bean名
     * @return
     */
    protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName) {
        // 判断是否为单例
        if (factory.isSingleton()) {
            // 单例从单例对象缓存获取对象
            Object object = this.factoryBeanObjectCache.get(beanName);
            // 判断从缓存中获取的对象是否为空
            if (object == null) {
                // 从FactoryBean获取对象
                object = doGetObjectFromFactoryBean(factory, beanName);
                // 添加到单例对象缓存
                this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
            }
            return (object != NULL_OBJECT ? object : null);
        } else {
            // 原型从FactoryBean获取对象
            return doGetObjectFromFactoryBean(factory, beanName);
        }
    }

    /**
     * 从FactoryBean获取对象
     *
     * @param factory  FactoryBean
     * @param beanName bean名
     * @return
     */
    private Object doGetObjectFromFactoryBean(final FactoryBean factory, final String beanName) {
        try {
            // 从FactoryBean获取对象
            return factory.getObject();
        } catch (Exception e) {
            throw new BeansException("FactoryBean threw exception on object[" + beanName + "] creation", e);
        }
    }
}
